package com.heima.media.service.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.dto.ResponseResult;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.minio.MinIOService;
import com.heima.common.util.SensitiveWordUtil;
import com.heima.media.dto.ArticleDto;
import com.heima.media.dto.ContentDto;
import com.heima.media.dto.ImageDto;
import com.heima.media.entity.WmChannel;
import com.heima.media.entity.WmNews;
import com.heima.media.entity.WmSensitive;
import com.heima.media.entity.WmUser;
import com.heima.media.feign.ArticleFeign;
import com.heima.media.service.*;
import org.apache.commons.io.IOUtils;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class AuditServiceImpl implements IAuditService {

    

    //自动审核
    @Async //当前方法需要使用线程来执行
    public void audit(WmNews wmNews) {
        System.out.println(Thread.currentThread().getName()+"开始执行审核........newsId="+wmNews.getId());
        //判断当前文章的状态

        // 如果状态是4  8 开始进入文章发布
        if (wmNews.getStatus()==4||wmNews.getStatus() == 8) {
            //判断如果还没有到发布时间，将文章状态改为8 审核通过（待发布） 发送延迟任务（消息）
            if (wmNews.getPublishTime().getTime()>System.currentTimeMillis()){
                wmNews.setStatus(8);
                newsService.updateById(wmNews);
                sendDelayMessage(wmNews);
            }else {
                // 调用文章服务接口保存文章
                publishArticle(wmNews);
            }
            return;
        }
        //如果状态是1  进入自动审核流程
        if (wmNews.getStatus()==1) {
            //提取内容中文本和图片
            Map<String, Object> map = getTextAndImageFromContent(wmNews.getContent());
            //获取文本内容
            String text = (String) map.get("text");
            //获取图片内容
            List<String> image = (List<String>) map.get("image");

            //敏感词
            boolean sensResult = checkSens(wmNews, text);
            if (!sensResult) return;

            //调用阿里云文本审核
            boolean textResult = checkText(wmNews, text);
            if (!textResult) return;
            //调用阿里云图片审核
            boolean imaeResult = checkImage(wmNews, image);
            if (!imaeResult) return;
            //判断如果还没有到发布时间，将文章状态改为8 审核通过（待发布） 发送延迟任务（消息）
            if (wmNews.getPublishTime().getTime()>System.currentTimeMillis()){
                wmNews.setStatus(8);
                newsService.updateById(wmNews);
                sendDelayMessage(wmNews);
            }else {
                // 调用文章服务接口保存文章
                publishArticle(wmNews);
            }
        }
        System.out.println(Thread.currentThread().getName() + " 执行审核完成.");

    }
    @Autowired
    RedissonClient client;
    //发送消息
    private void sendDelayMessage(WmNews wmNews) {
        //获取一个阻塞队列，指定队列的名称
        RBlockingQueue<String> blockingQueue= client.getBlockingQueue("article_publish");
        //创建一个延迟队列  指定使用那个阻塞队列
        RDelayedQueue<String> delayedQueue=client.getDelayedQueue(blockingQueue);
        //发送延迟消息，指定消息内容  延迟时间，时间单位
        //延迟时间为文章的发布时间-当前系统时间
        long time = wmNews.getPublishTime().getTime() - System.currentTimeMillis();
        delayedQueue.offer(JSON.toJSONString(wmNews), time,TimeUnit.MILLISECONDS);
    }

    @Autowired
    private IWmSensitiveService sensitiveService;

    //敏感词库
    private boolean checkSens(WmNews wmNews, String text) {
        //判断是否已经存在敏感词数据
        if (SensitiveWordUtil.dictionaryMap.size()==0) {
            //查询所有的敏感词
            LambdaQueryWrapper<WmSensitive> qw=new LambdaQueryWrapper<>();
            qw.select(WmSensitive::getSensitives);
            List<String> strings = sensitiveService.listObjs(qw, o -> o.toString());
            SensitiveWordUtil.initMap(strings);
        }
        //审核标题+标签+内容
        Map<String, Integer> map = SensitiveWordUtil.matchWords(wmNews.getTitle() + wmNews.getLabels() + text);
        if(map.size()>0){
            wmNews.setStatus(2);
            Set<String> keySet = map.keySet();
            String join = String.join(" ", keySet);
            wmNews.setReason("敏感词审核不通过:"+join);
            newsService.updateById(wmNews);
            return false;
        }
        return true;
    }

    @Autowired
    IWmUserService userService;
    @Autowired
    IWmChannelService channelService;
    @Autowired
    ArticleFeign articleFeign;
    // 调用文章服务接口保存文章
    private void publishArticle(WmNews wmNews) {
        ArticleDto dto=new ArticleDto();
        //设置文章数据
        BeanUtils.copyProperties(wmNews,dto);
        dto.setId(null);
        //获取作者id  查询用户
        WmUser wmUser = userService.getById(wmNews.getUserId());
        dto.setAuthorId(wmUser.getApAuthorId());
        dto.setAuthorName(wmUser.getName());
        //查询频道信息
        WmChannel wmChannel = channelService.getById(wmNews.getChannelId());
        dto.setChannelName(wmChannel.getName());
        dto.setLayout(wmNews.getType());
        dto.setFlag(0);
        //前端显示的图片格式 :http://xxx.jpg,http://xxx.jpg
        //封面图片需要转换
        List<ImageDto> imageDtos = JSON.parseArray(wmNews.getImages(), ImageDto.class);
        ArrayList<String> list = new ArrayList<>();
        for (ImageDto imageDto : imageDtos) {
            list.add(imageDto.getUrl());
        }
        //将集合转换成都好分割的字符串
        String join = String.join(",", list);
        dto.setImages(join);
        //远程调用
        ResponseResult<Long> result = articleFeign.saveArticle(dto);
        //判断结果
        if (result.getCode().equals(AppHttpCodeEnum.SUCCESS.getCode())) {
            Long aLong = result.getData();
            //将文章id写回到自媒体文章表中，并且修改状态为9
            wmNews.setArticleId(aLong);
            wmNews.setStatus(9);
            newsService.updateById(wmNews);
        }
    }

    @Autowired
    MinIOService minIOService;
    @Autowired
    GreenImageScan imageScan;

    //调用阿里云图片审核
    private boolean checkImage(WmNews wmNews, List<String> image) {
        //需要审核的图片包含内容和封面
        //获取封面图片
        List<ImageDto> list = JSON.parseArray(wmNews.getImages(), ImageDto.class);
        //便利
        for (ImageDto imageDto : list) {
            //判断封面图片是否已经存在于内容图片中
            if (!image.contains(imageDto.getUrl())) {
                //将封面图片加入到最终要审核的图片集合中
                if(!StringUtils.isEmpty(imageDto.getUrl())){
                    image.add(imageDto.getUrl());
                }
            }
        }
        //判断图片集合是否有图片
        if (image.size()==0) {
            return true;
        }
        boolean result=false;
        //因为MinIO服务没有外网地址，所以需要先下载图片内容
        try {
            ArrayList<byte[]> list1 = new ArrayList<>();
            //遍历图片集合，到MinIO下载
            for (String s : image) {
                InputStream stream = minIOService.download(s);
                //将stream转换成字节数组
                byte[] bytes = IOUtils.toByteArray(stream);
                list1.add(bytes);
            }
            Map map = imageScan.imageScan(list1);
            //分析结果 suggestion
            String suggestion = (String) map.get("suggestion");
            //suggestion结果
            switch (suggestion){
                case "pass":
                    //正常
                    result=true;
                    break;
                case "block":
                    //违规 修改文章状态为2，记录失败原因
                    wmNews.setStatus(2);
                    String label = (String) map.get("label");
                    wmNews.setReason("阿里云图片审核失败: "+label);
                    //更新状态
                    newsService.updateById(wmNews);
                    break;
                case "review":
                    //不确定  人工审核
                    wmNews.setStatus(3);
                    newsService.updateById(wmNews);
                    break;
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    @Autowired
    private GreenTextScan textScan;
    @Autowired
    private IWmNewsService newsService;
    //调用阿里云文本审核
    private Boolean checkText(WmNews wmNews, String text) {
        boolean result=false;
        //文本审核需要审核  标题+标签+正文中的文字
        String content = wmNews.getTitle() + wmNews.getLabels() + text;
        try {
            Map map = textScan.greenTextScan(content);
            //分析结果 suggestion
            String suggestion = (String) map.get("suggestion");
            //suggestion结果
            switch (suggestion){
                case "pass":
                    //正常
                    result=true;
                    break;
                case "block":
                    //违规 修改文章状态为2，记录失败原因
                    wmNews.setStatus(2);
                    String label = (String) map.get("label");
                    wmNews.setReason("阿里云文本审核失败: "+label);
                    //更新状态
                    newsService.updateById(wmNews);
                    break;
                case "review":
                    //不确定  人工审核
                    wmNews.setStatus(3);
                    newsService.updateById(wmNews);
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    //提取内容中文本和图片
    private Map<String, Object> getTextAndImageFromContent(String content) {
        //定义返回结果
        HashMap<String, Object> map = new HashMap<>();
        //定义文本内容
        StringBuilder builder = new StringBuilder();
        //定义图片集合
        ArrayList<String> images = new ArrayList<>();
        //将内容转换成ContentDto集合
        List<ContentDto> contentDtos = JSON.parseArray(content, ContentDto.class);
        //遍历
        for (ContentDto contentDto : contentDtos) {
            if (contentDto.getType().equals("text")) {
                builder.append(contentDto.getValue());
            }else{
                images.add(contentDto.getValue());
            }
        }
        map.put("text",builder.toString());
        map.put("image",images);
        return map;
    }
}
